/**
 * Copyright (C) 2009 Stefan Maassen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.indisopht.guice.groovy.spi;

import java.util.concurrent.TimeUnit;

import com.google.inject.Provider;

import de.indisopht.guice.groovy.spi.internal.GroovyProvider;

/**
 * Provides access to groovy classes on a provider per class basis. 
 * Currently supports classes and scripts from files or directly 
 * given as source code.
 *      
 * @author Stefan Maassen
 * @since 0.3.0
 *
 */
public class GroovyIntegration {
    
    /**
     * Entry point for creating a provider for <code>somethingGroovy<code> using the given name pointing to a file or
     * by parsing the given string as a class. <br>
     * <br>
     * Example usage:<br>
     * 
     * <pre>
     * <b>Binding a groovy class to a java class:</b>
     * <code>bind(MyClass.class)
     *          .toProvider(GroovyIntegration.&lt;MyClass&gt;fromGroovy(&quot;com.mypackage.MyGroovyClass&quot;))
     *          .get();</code>
     * 
     * <b>Binding grovvy code inside a string to a java class</b>
     * <code>bind(MyClass.class)
     *          .toProvider(GroovyIntegration.&lt;MyClass&gt;fromGroovy(&quot;import a.b.c; class B extends MyClass { }&quot;))
     *          .get();</code>
     *
     * <b>Binding a grovvy script inside a string</b>
     * <code>bind(Script.class)
     *          .toProvider(GroovyIntegration.&lt;Script&gt;fromGroovy(&quot;println('groovy hello'); 'groovy'&quot;))
     *          .get();</code>
     *
     * <b>Binding a grovvy script from a file</b>
     * <code>bind(Script.class)
     *          .toProvider(GroovyIntegration.&lt;Script&gt;fromGroovy(&quot;/path/to/TestScript.groovy&quot;))
     *          .get();</code>
     * </pre>
     * <pre>
     * NOTE: <code>MyClass<code> must be known at runtime, when binding to Groovy.
     * </pre> 
     */
    public static <T> ExtendedConfiguration<T> fromGroovy(final String somethingGroovy) {
        return new ExtendedConfiguration<T>(somethingGroovy);
    }
    
    public static class ExtendedConfiguration<T> {
        
        private final String somethingGroovy;
        
        /**
         * @param className
         */
        private ExtendedConfiguration(String className) {
            super();
            this.somethingGroovy = className;
        }
        
        /**
         * Returns a {@link com.google.inject.Provider}. 
         * If recompilation is enabled, recompiled instance is returned when next
         * instance provision is triggered (a.k.a. get() is called).
         * 
         * @return {@link com.google.inject.Provider}
         * 
         * @see de.indisopht.guice.groovy.spi.internal.GroovyProvider
         */
        public Provider<T> get() {
            return new GroovyProvider<T>(somethingGroovy);
        }
        
        /**
         * Returns a proxied {@link com.google.inject.Provider}. 
         * If recompilation is enabled, source file will be checked every 5 seconds for 
         * recompilation and recompiled instance is used automagically. 
         * 
         * @return {@link com.google.inject.Provider}
         * 
         * @see de.indisopht.guice.groovy.spi.internal.GroovyProvider
         * @see de.indisopht.guice.groovy.spi.interceptors.RecompilationInterceptor
         */
        public Provider<T> pushRecompilation() {
            return new GroovyProvider<T>(somethingGroovy, true);
        } 

        /**
         * Returns a proxied {@link com.google.inject.Provider}. 
         * If recompilation is enabled, source file will be checked every given time interval 
         * for recompilation and recompiled instance is used automagically. 
         * 
         * @param recompilationInterval the amount of time until next recompilation check
         * @param tu unit of time for recompilation
         * 
         * @return {@link com.google.inject.Provider}
         * 
         * @see de.indisopht.guice.groovy.spi.internal.GroovyProvider
         * @see de.indisopht.guice.groovy.spi.interceptors.RecompilationInterceptor
         */
        public Provider<T> pushRecompilationEvery(long recompilationInterval, TimeUnit tu) {
            return new GroovyProvider<T>(somethingGroovy, recompilationInterval, tu);
        }
    }
}
